Big Picture: Two Paths, One S3 Bucket
Your EC2 instance sits in a private subnet and needs to upload reports to an S3 bucket. It can reach S3 in two main ways:
VPC Endpoint – Private Path
Recommended- No public IP, no Internet hop.
- Traffic stays on the AWS backbone via a Gateway VPC Endpoint.
- Cheaper data transfer for S3 + stronger security posture.
NAT Gateway – Public Path
Fallback / Legacy- EC2 sends traffic to a NAT Gateway in a public subnet.
- NAT uses an Elastic IP via the Internet Gateway to reach S3.
- More cost + Internet exposure; acceptable but not ideal for internal workloads.
Security Model
IAM + VPCE + Bucket Policy- IAM role on EC2 → who you are.
- Bucket policy → who may enter the bucket.
- VPC endpoint policy → who may use the private door.
- Combine all three to lock S3 down to the workload and the VPC.
Route Tables – Why VPC Endpoint Wins
The longest prefix match rule decides whether S3 traffic goes to the VPC Endpoint or NAT Gateway.
Private Subnet Route Table
For EC2 (10.0.1.0/24)- S3 traffic matches the prefix list route (more specific) → VPC Endpoint.
- Only “everything else” uses 0.0.0.0/0 → NAT.
Public Subnet Route Table
For NAT Subnet- NAT sends outgoing traffic to the Internet Gateway.
- From there, traffic reaches S3 public endpoints.
Decision Summary
- Have S3 prefix list → VPC Endpoint? → Private path wins.
- No S3-specific route? → EC2 uses NAT + IGW.
- Mixed mode is common in brownfield environments.
Architecture – VPC, Subnets, NAT, VPCE, S3
High-level layout for a single-AZ teaching scenario (you can extend to multi-AZ easily).
VPC Layout
- VPC:
10.0.0.0/16 - Public Subnet:
10.0.0.0/24(NAT Gateway) - Private Subnet:
10.0.1.0/24(EC2 instance) - Internet Gateway attached to VPC.
Key Components
- EC2 (private subnet, no public IP).
- NAT Gateway (public subnet, Elastic IP).
- VPC Gateway Endpoint for S3.
- S3 bucket
my-logs-bucketin the same Region.
Business Story
- Finance EC2 instance generates nightly sales reports.
- Uploads them to S3 for long-term storage and analytics.
- Security team wants: no public S3, no direct Internet from EC2.
- Solution: force traffic via VPC Endpoint + restricted bucket policy.
Simulation – Curved Path from EC2 to S3
Watch the packet travel along curved paths. Blue = VPC Endpoint (private), Yellow = NAT + IGW (public). The log panel shows a CloudWatch-style trace of each hop.
Private Subnet
com.amazonaws.ap-southeast-1.s3
Public Subnet + EIP
my-logs-bucket
Run the Simulation
Click a button below to send a “report upload” from EC2 to S3.
- S3 traffic matches the S3 prefix list route → VPC Endpoint (blue path).
- If that route is missing/misconfigured, 0.0.0.0/0 → NAT (yellow path).
- CloudWatch logs help you detect “unexpected” NAT usage to S3.
IAM Role & Bucket Policy
Networking decides how you reach S3. IAM and bucket policies decide whether you may do so.
EC2 Instance Profile Role
Trust Policy{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:PutObject","s3:GetObject"],
"Resource": "arn:aws:s3:::my-logs-bucket/*"
}]
}
Bucket Policy – Lock to VPC Endpoint
Bucket Policy{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": ["s3:GetObject","s3:PutObject"],
"Resource": "arn:aws:s3:::my-logs-bucket/*",
"Condition": {
"StringEquals": {
"aws:SourceVpce": "vpce-1234567890abcdef"
}
}
}]
}
Flow Summary
Quick Quiz
Use this as a formative check during class.
CLI & Boto3 – Upload Example
Same IAM role, different network path – the application code doesn’t change.
AWS CLI from EC2
aws s3 cp report-2025-11-30.json s3://my-logs-bucket/reports/ \ --region ap-southeast-1
- Instance profile role provides credentials automatically.
- Network path (VPCE or NAT) is determined by route tables.
Python Boto3 Snippet
import boto3
s3 = boto3.client("s3")
s3.upload_file(
Filename="report-2025-11-30.json",
Bucket="my-logs-bucket",
Key="reports/report-2025-11-30.json"
)
- No endpoint hard-coded → easier to switch from NAT to VPCE.
- Good pattern for refactoring legacy workloads.
Failure Mode – When Policies Don’t Agree
Use this as a mini runbook: “EC2 cannot upload to S3, but ping works.”
Common Problems
- VPC Endpoint exists, but route table not updated.
- Bucket policy missing
aws:SourceVpceor using wrong VPCE ID. - IAM role lacks
s3:PutObjectpermission.
Classroom Exercise
- Break: remove S3 prefix route → traffic goes via NAT.
- Observe: animation switches to yellow path; logs show NAT usage.
- Fix: restore S3 prefix route + bucket policy; verify blue path again.